package uk.co.hs.web.controller.admin;

import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.propertyeditors.CustomBooleanEditor;
import org.springframework.beans.propertyeditors.CustomNumberEditor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.RedirectView;

import uk.co.hs.constants.AdminGeneralConstants;
import uk.co.hs.service.admin.interfaces.AdminServiceInterface;
import uk.co.hs.web.command.admin.AdminListCommand;
import uk.co.hs.web.util.AdminListDTO;

/**
 * AdminListController.
 */
@Controller
@SessionAttributes("hs_adminListCommand")
public abstract class AdminListController
{
  public AdminServiceInterface mAdminService;
  public String mControllerName, mObjectName;
  public List<Object> mColumnMessageCodes;
  public List<Object> mColumnWidths;
  public String mViewName;
  public int mNumberOfIdentifiers;

  public AdminListController()
  {
    setColumnWidths();
    setColumnMessageCodes();
    setControllerName();
    setNumberOfIdentifiers();
    setObjectName();
    setViewName();
  }

  /**
   * @see org.springframework.web.servlet.mvc.BaseCommandController
   *  #initBinder(javax.servlet.http.HttpServletRequest,
   *              org.springframework.web.bind.ServletRequestDataBinder)
   * {@inheritDoc}
   */
  @InitBinder
  public void initBinder(ServletRequestDataBinder aBinder) throws Exception
  {
    CustomNumberEditor numEditor = new CustomNumberEditor(Long.class, true);
    aBinder.registerCustomEditor(Long.class, numEditor);

    CustomBooleanEditor booleanEditor = new CustomBooleanEditor(true);
    aBinder.registerCustomEditor(Boolean.class, booleanEditor);
  }

  /**
   * Gets the model attribute "items".
   *
   * @return List of AdminListDTO objects.
   */
  @ModelAttribute("items")
  public List<AdminListDTO> getAllSortedRecords()
  {
    return mAdminService.getAllSortedRecords();
  }

  /**
   * Gets the model attribute "columnMessageCodes".
   *
   * @return List of String objects.
   */
  @ModelAttribute("columnMessageCodes")
  public List<Object> columnMessageCodes()
  {
    return mColumnMessageCodes;
  }

  /**
   * Gets the model attribute "columnWidths".
   *
   * @return List of Integer objects.
   */
  @ModelAttribute("columnWidths")
  public List<Object> columnWidths()
  {
    return mColumnWidths;
  }

  /**
   * Form Backing Object Method (get).
   *
   * @param aRequest HttpServletRequest object.
   * @return ModelAndView for the initial load of the page.
   * @throws Exception Exception thrown if an error occurs.
   */
  public ModelAndView formBackingObject(HttpServletRequest aRequest,
                                        Boolean aCanCreateNew,
                                        Boolean aCanView) throws Exception
  {
    aRequest.setAttribute("title", mObjectName + " List");
    AdminListCommand command = new AdminListCommand();

    List<Object> list = new ArrayList<Object>();
    for (int i = 0; i < mNumberOfIdentifiers; i++)
    {
      list.add(null);
    }
    command.setIdentifier(list);
    command.setCanCreateNew(aCanCreateNew);
    command.setCanView(aCanView);

    ModelAndView mav = new ModelAndView(getViewName());
    mav.addObject(command);
    return mav;
  }

  /**
   * On Submit Method (post).
   *
   * @param aRequest HttpServletRequest object.
   * @param aCommand Command object.
   * @return ModelAndView for the redirected page.
   */
  @RequestMapping(method = RequestMethod.POST)
  public ModelAndView onSubmit(HttpServletRequest aRequest,
                               @ModelAttribute(AdminGeneralConstants.COMMAND_NAME) AdminListCommand aCommand)
  {
    aRequest.setAttribute("title", mObjectName + " List");
    ModelAndView mav = new ModelAndView(new RedirectView(getEditUrl()));
    AdminListCommand command = (AdminListCommand) aCommand;
    Object currentIdentifier;
    for (int i = 0; i < command.getIdentifier().size(); i++)
    {
      currentIdentifier = command.getIdentifier().get(i);
      if (currentIdentifier != null && !currentIdentifier.toString().equals("null"))
    	{
      	mav.addObject("id_" + i, currentIdentifier);
    	}
    }
    return mav;
  }

  /**
   *
   * @param aStringToFormat String
   * @return String
   */
  @SuppressWarnings("unused")
  private String removeSpaces(String aStringToFormat)
  {
    StringTokenizer tokenizedString = new StringTokenizer(aStringToFormat, " ", false);
    String result = "";
    while (tokenizedString.hasMoreElements())
    {
      result += tokenizedString.nextElement();
    }
    return result;
  }

  /**
   *
   * @return String
   */
  private String getEditUrl()
  {
    String formattedControllerName;
    if (allCapitals())
    {
      formattedControllerName = mControllerName.toLowerCase();
    }
    else
    {
      char firstChar = mControllerName.charAt(0);
      firstChar = Character.toLowerCase(firstChar);
      formattedControllerName = firstChar + mControllerName.substring(1);
    }
    return formattedControllerName + "Edit.htm";
  }

  /**
   *
   * @return boolean
   */
  private boolean allCapitals()
  {
    int charCount = mControllerName.length();
    for (int i = 0; i < charCount; i++)
    {
      if (Character.isLowerCase(mControllerName.charAt(i)))
      {
        return false;
      }
    }
    return true;
  }

  /**
   * @return the view name.
   */
  private String getViewName()
  {
    return mViewName;
  }

  abstract void setViewName();

  abstract void setColumnWidths();

  abstract void setColumnMessageCodes();

  abstract void setControllerName();

  abstract void setNumberOfIdentifiers();

  abstract void setObjectName();

  /**
   * General Exception handler.
   *
   * @param aException Exception thrown.
   * @return Error ModelAndView.
   */
  @ExceptionHandler(Exception.class)
  protected ModelAndView handleException(Exception aException)
  {
    return new ModelAndView("hs_Error").addObject("exception", aException);
  }
}
